package org.will.ftppool;

import com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Arrays;
import java.util.List;

/**
 * @Author wangwei-ww
 * @Date 2017/6/29 19:58
 * @Comment
 */
public class FTPTemplate extends AbstractFTPTemplate {

    @Override
    public List<String> listFiles(String path, int limit) throws Exception {
        if (logger.isDebugEnabled()) {
            logger.debug("正在获取文件列表,path:{}", path);
        }
        FTPClient client = null;

        List<String> fileList = null;
        try {
            client = getFTPClient();
            boolean ret = changeDirectory(client, path);
            if (ret) {
                String[] fileNames = client.listNames();
                if (fileNames == null) {
                    logger.error("获取不到文件列表,PATH:{}", path);
                } else {
                    int capactiy = Math.min(limit, fileNames.length);
                    String[] fileNamesCopy = Arrays.copyOfRange(fileNames, 0, capactiy);
                    fileList = Arrays.asList(fileNamesCopy);
                }
            }
            return fileList;
        } catch (Exception e) {
            logger.error("获取文件列表异常", e);
            if (client != null) {
                getFtpClientPool().invalidateObject(client);
                client = null;
            }
            throw e;
        } finally {
            //return to object pool
            if (client != null) {
                getFtpClientPool().returnObject(client);
            }
        }
    }

    @Override
    public void getFileCallback(String path, String fileName, IFTPCallback<FTPFile, Boolean> callback) throws Exception {

    }

    @Override
    public boolean putFile(String path, byte[] bytes, String fileName) throws Exception {
        if (logger.isDebugEnabled()) {
            logger.debug("正在上传文件{}到{}", fileName, path);
        }
        FTPClient client = getFTPClient();
        boolean ret = changeDirectory(client, path); //切换目录失败无异常
        BufferedInputStream inStream = null;
        boolean success = false;
        try {
            if (ret) {
                inStream = new BufferedInputStream(new ByteArrayInputStream(bytes));
                success = client.storeFile(fileName, inStream);
            }
            return success;
        } catch (Exception e) {
            logger.error("正在上传文件{}异常", fileName, e);
            getFtpClientPool().invalidateObject(client);
            client = null;
        } finally {
            if (inStream != null) {
                try {
                    inStream.close();
                } catch (IOException e) {
                    logger.error("关闭文件流时发生异常", e);
                }
            }
            if (client != null) {
                getFtpClientPool().returnObject(client);
            }
        }
        return success;
    }

    @Override
    public boolean deleteFile(String path, String fileName) throws Exception {
        if (logger.isDebugEnabled()) {
            logger.debug("正在删除{}文件,ftpconfig:{}", fileName, getFtpClientPool().getFactory().getConfig());
        }
        FTPClient client = getFTPClient();
        boolean ret = changeDirectory(client, path);
        try {
            if (ret) {
                return client.deleteFile(fileName);
            }
            return false;
        } catch (Exception e) {
            logger.error("删除文件异常,fileName:{}", fileName, e);
            getFtpClientPool().invalidateObject(client);
            client = null;
            throw e;
        } finally {
            if (client != null) {
                getFtpClientPool().returnObject(client);
            }
        }
    }

    @Override
    protected String performPerFileToString(FTPClient client, String fileName, String encoding) throws Exception {
        InputStream inputstream = null;
        String content;
        encoding = encoding == null ? "UTF-8" : encoding;
        try {
            inputstream = new ByteArrayInputStream(downloadFileByBytes(client, fileName));
            content = IOUtils.toString(inputstream, encoding);
        } catch (Exception e) {
            logger.error("Perform file To String error " + client.getRemoteAddress(), e);
            throw e;
        } finally {
            if (inputstream != null) {
                inputstream.close();
            }
        }

        return content;
    }

    @Override
    protected byte[] downloadFileByBytes(FTPClient client, String fileName) throws Exception {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        byte[] fileBytes = null;
        try {
            boolean downSuc = client.retrieveFile(fileName, os);
            if (!downSuc) {
                throw new Exception("下载报文失败:" + fileName);
            }
            fileBytes = os.toByteArray();
        } catch (Exception e) {
            logger.error("ftp 通信错误 或 文件IO出错, 下载文件成功状态:" + client.getRemoteAddress(), e);
            throw e;
        } finally {
            if (os != null) {
                os.close();
            }
        }
        return fileBytes;
    }


    public FTPTemplate(FTPClientPool pool) {
        this.ftpClientPool = pool;
    }

    public FTPTemplate() {
    }
}
